// bleManager.js - 蓝牙通信管理器
import * as comm from '../utils/common';
class BleManager {
  constructor() {
    // 初始化编码器/解码器
    this.textEncoder = null;
    this.textDecoder = null;

    this.deviceId = '';
    this.serviceId = '';
    this.writeCharId = '';
    this.readCharId = '';
    this.isConnected = false;
    this.isConnecting = false;

    // 分包相关变量
    this.packetBuffer = null;
    this.expectedPacketSeq = 0;
    this.totalPackets = 0;
    this.receivedPackets = 0;
    this.packetCallback = null;

    // 配置
    this.MAX_PACKET_SIZE = 20;
    this.PACKET_HEADER = 0xAA;

    // 错误处理
    this.errorCallbacks = [];
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 3;
  }

  // 初始化蓝牙
  async initBluetooth() {
    try {
      const res = await this.promisify(wx.openBluetoothAdapter)();
      console.log('✅ 蓝牙初始化成功');
      this._setupBluetoothListeners();
      return {
        success: true
      };
    } catch (err) {
      console.error('❌ 蓝牙初始化失败:', err);
      return this._handleError('INIT_FAILED', '蓝牙初始化失败，请检查手机蓝牙是否开启', err);
    }
  }

  // 设置蓝牙监听器
  _setupBluetoothListeners() {
    // 适配器状态变化
    wx.onBluetoothAdapterStateChange((res) => {
      console.log('蓝牙适配器状态变化:', res);
      if (!res.available) {
        this._handleError('ADAPTER_UNAVAILABLE', '蓝牙适配器不可用');
      }
    });

    // 设备发现
    wx.onBluetoothDeviceFound((res) => {
      res.devices.forEach(device => {
        if (device.name && device.name.includes('Test')) {
          this.onDeviceFound(device);
        }
      });
    });

    // 连接状态变化
    wx.onBLEConnectionStateChange((res) => {
      console.log('连接状态变化:', res);
      if (!res.connected) {
        this.isConnected = false;
        this._handleError('DISCONNECTED', '设备连接已断开');
        this._tryReconnect();
      } else {
        this.isConnected = true;
        this.reconnectAttempts = 0;
      }
    });

    // 特征值变化
    wx.onBLECharacteristicValueChange((res) => {
      this._onCharacteristicValueChange(res);
    });
  }


  // 搜索设备
  async startDiscovery() {
    try {
      // 先停止之前的搜索
      await this.promisify(wx.stopBluetoothDevicesDiscovery)();

      // 开始新搜索
      await this.promisify(wx.startBluetoothDevicesDiscovery)({
        //services: [this.serviceId],
        allowDuplicatesKey: true,
        interval: 0,
        duration: 5000
      });

      console.log('🔍 开始搜索设备...');
      return {
        success: true
      };
    } catch (err) {
      return this._handleError('DISCOVERY_FAILED', '设备搜索失败', err);
    }
  }

  // 停止搜索
  async stopDiscovery() {
    try {
      await this.promisify(wx.stopBluetoothDevicesDiscovery)();
      return {
        success: true
      };
    } catch (err) {
      console.error('停止搜索失败:', err);
      return {
        success: false,
        error: err
      };
    }
  }

  // 连接设备
  async connectDevice(deviceId) {
    if (this.isConnecting) {
      return {
        success: false,
        error: '正在连接中...'
      };
    }

    this.isConnecting = true;

    try {
      // 创建连接
      await this.promisify(wx.createBLEConnection)({
        deviceId
      });
      this.deviceId = deviceId;
      this.isConnected = true;

      try {
        const setBluRes = await this.promisify(wx.setBLEMTU)({
          deviceId: deviceId,
          mtu: 500
        });
        console.log("setBluRes", setBluRes)
      } catch (e) {
        console.log("setBluRes fail", e)
      }


      const bluRes = await this.promisify(wx.getBLEMTU)({
        deviceId: deviceId,
        writeType: 'write'
      });
      console.log("bluRes", bluRes)
      /*comm.httpGet("/device/test?mtu=" + bluRes.mtu, function (res) {
      })*/
      if (bluRes.mtu > 203) {
        this.MAX_PACKET_SIZE = 200;
      } else {
        this.MAX_PACKET_SIZE = bluRes.mtu - 3;
      }

      // 获取服务
      const services = await this.promisify(wx.getBLEDeviceServices)({
        deviceId
      });
      const targetService = services.services.find(service => {
        // 这里使用ESP32端设置的服务UUID
        return service.uuid.indexOf('FFF0') !== -1;
      });

      if (!targetService) {
        throw new Error('未找到目标服务');
      }
      this.serviceId = targetService.uuid;
      console.log("serviceId", this.serviceId)
      // 获取特征值
      const characteristics = await this.promisify(wx.getBLEDeviceCharacteristics)({
        deviceId,
        serviceId: targetService.uuid
      });
      console.log("characteristics", characteristics)
      // 查找读写特征值
      characteristics.characteristics.forEach(characteristic => {
        const properties = characteristic.properties;

        if (properties.write) {
          this.writeCharId = characteristic.uuid;
        }
        if (properties.notify || properties.indicate) {
          this.readCharId = characteristic.uuid;
        }

      });
      if (!this.writeCharId || !this.readCharId) {
        throw new Error('未找到必要的特征值');
      }

      // 启用通知
      await this.promisify(wx.notifyBLECharacteristicValueChange)({
        deviceId,
        serviceId: targetService.uuid,
        characteristicId: this.readCharId,
        state: true
      });

      console.log('✅ 设备连接和配置完成');
      this.isConnecting = false;
      return {
        success: true
      };

    } catch (err) {
      this.isConnecting = false;
      return this._handleError('CONNECTION_FAILED', '设备连接失败', err);
    }
  }

  // 发送数据（自动分包）
  async sendData(data, callback = null) {
    if (!this.isConnected) {
      return this._handleError('NOT_CONNECTED', '设备未连接');
    }

    try {
      const arrayBuffer = this.stringToArrayBuffer(data);
      // 分包发送
      return await this._sendPackets(arrayBuffer, callback);
    } catch (err) {
      return this._handleError('SEND_FAILED', '数据发送失败', err);
    }
  }

  // 发送多包数据
  async _sendPackets(arrayBuffer, callback) {
    const dataView = new Uint8Array(arrayBuffer);
    const totalPackets = Math.floor((arrayBuffer.byteLength + (this.MAX_PACKET_SIZE - 4) - 1) / (this.MAX_PACKET_SIZE - 4));
    let offset = 0;
    for (let seq = 0; seq < totalPackets; seq++) {
      const isLast = (seq == totalPackets - 1)
      const chunkSize = isLast ?
        (dataView.length - offset) :
        (this.MAX_PACKET_SIZE - 4);
      console.log("chunkSize",totalPackets,chunkSize)
      const packet = new Uint8Array(4 + chunkSize);
      packet[0] = this.PACKET_HEADER;
      packet[1] = seq;
      packet[2] = totalPackets;
      packet[3] = chunkSize;
      for (let i = 0; i < chunkSize; i++) {
        packet[4 + i] = dataView[offset + i];
      }
      const result = await this._writeCharacteristic(packet.buffer);
      if (!result.success) {
        return result;
      }
      offset += chunkSize;
      // 进度回调
      if (callback && typeof callback.onProgress === 'function') {
        callback.onProgress(seq + 1, totalPackets);
      }
      // 分包间延迟
      await this.delay(20);
    }

    return {
      success: true
    };
  }

  // 写入特征值
  async _writeCharacteristic(buffer) {
    try {
      await this.promisify(wx.writeBLECharacteristicValue)({
        deviceId: this.deviceId,
        serviceId: this.serviceId,
        characteristicId: this.writeCharId,
        value: buffer
      });
      return {
        success: true
      };
    } catch (err) {
      return this._handleError('WRITE_FAILED', '特征值写入失败', err);
    }
  }

  // 处理特征值变化（数据接收）
  _onCharacteristicValueChange(res) {
    try {
      const data = new Uint8Array(res.value);
      // 基本校验
      if (data.length < 4 || data[0] !== this.PACKET_HEADER) {
        console.error('无效数据包', data.length, data[0], data[data.length - 1]);
        return;
      }
      const seq = data[1];
      const total = data[2];
      const dataLength = data[3];
      console.log("_onCharacteristicValueChange", seq, total, dataLength)
      this._handlePacket(data);
    } catch (err) {
      console.error('数据处理错误:', err);
    }
  }

  // 开始分包接收
  _startPacketReception(totalPackets, data, dataLength) {
    this.totalPackets = totalPackets;
    this.expectedPacketSeq = 1;
    this.receivedPackets = 1;
    this.packetBuffer = new Uint8Array(4096); // 假设最大256字节
    this.packetBuffer.set(data.slice(5, 5 + dataLength), 0);
  }

  // 处理包
  _handlePacket(data) {
    const seq = data[1];
    const total = data[2];
    const dataLength = data[3];
    if (seq !== this.expectedPacketSeq) {
      console.error('包序列号不匹配，期望:', this.expectedPacketSeq, '实际:', seq);
      this._resetPacketReception();
      return;
    }
    if (seq == 0) {
      this.packetBuffer = new Uint8Array(4096); // 假设最大256字节
    }
    const startIndex = this.receivedPackets * (this.MAX_PACKET_SIZE - 4);
    this.packetBuffer.set(data.slice(4, 4 + dataLength), startIndex);
    this.expectedPacketSeq++;
    this.receivedPackets++;
    if (this.expectedPacketSeq == total) {
      const totalLength = startIndex + dataLength;
      const completeData = this.arrayBufferToString(this.packetBuffer.buffer, 0, totalLength);
      this._emitDataReceived(completeData);
      this._resetPacketReception();
    }
  }


  // 处理错误响应
  _handleErrorResponse(errorCode) {
    const errorMsg = this._getErrorMessage(errorCode);
    this._handleError('DEVICE_ERROR', `设备返回错误: ${errorMsg}`);
  }

  // 重置分包接收状态
  _resetPacketReception() {
    this.packetBuffer = null;
    this.expectedPacketSeq = 0;
    this.totalPackets = 0;
    this.receivedPackets = 0;
  }

  // 发射数据接收事件
  _emitDataReceived(data) {
    if (this.packetCallback && typeof this.packetCallback.onData === 'function') {
      this.packetCallback.onData(data);
    }
    // 全局事件
    if (typeof this.onDataReceived === 'function') {
      this.onDataReceived(data);
    }
  }

  // 尝试重连
  async _tryReconnect() {
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.log('达到最大重连次数，停止重连');
      return;
    }

    this.reconnectAttempts++;
    console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);

    await this.delay(2000 * this.reconnectAttempts); // 指数退避

    if (this.deviceId) {
      this.connectDevice(this.deviceId).then(result => {
        if (result.success) {
          console.log('重连成功');
        }
      });
    }
  }

  // 错误处理
  _handleError(code, message, originalError = null) {
    console.error(`错误 [${code}]:`, message, originalError);

    const errorInfo = {
      code,
      message,
      originalError,
      timestamp: new Date().toISOString()
    };

    // 调用错误回调
    this.errorCallbacks.forEach(callback => {
      try {
        callback(errorInfo);
      } catch (err) {
        console.error('错误回调执行失败:', err);
      }
    });

    return {
      success: false,
      error: errorInfo
    };
  }

  // 获取错误信息
  _getErrorMessage(errorCode) {
    const errorMap = {
      0x01: '数据包解析错误',
      0x02: '数据长度超限',
      0x03: '设备忙，请稍后重试',
      0x04: '内存分配失败'
    };
    return errorMap[errorCode] || `未知错误 (0x${errorCode.toString(16)})`;
  }

  // 添加错误回调
  onError(callback) {
    if (typeof callback === 'function') {
      this.errorCallbacks.push(callback);
    }
  }

  // 断开连接
  async disconnect() {
    try {
      if (this.deviceId && this.isConnected) {
        await this.promisify(wx.closeBLEConnection)({
          deviceId: this.deviceId
        });
      }
      this.isConnected = false;
      this.deviceId = '';
      return {
        success: true
      };
    } catch (err) {
      return this._handleError('DISCONNECT_FAILED', '断开连接失败', err);
    }
  }

  // 工具函数
  promisify(api) {
    return (options = {}) => {
      return new Promise((resolve, reject) => {
        api({
          ...options,
          success: resolve,
          fail: reject
        });
      });
    };
  }

  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /*stringToArrayBuffer(str) {
    const buf = new ArrayBuffer(str.length);
    const bufView = new Uint8Array(buf);
    for (let i = 0; i < str.length; i++) {
      bufView[i] = str.charCodeAt(i);
    }
    return buf;
  }

  arrayBufferToString(buffer, offset = 0, length = null) {
    const uint8Array = new Uint8Array(buffer, offset, length);
    let encodedString = String.fromCharCode.apply(null, uint8Array);
    encodedString = decodeURIComponent(escape((encodedString))); //没有这一步中文会乱码
    return encodedString;
  }*/


  /**
   * 手动实现 UTF-8 编码
   */
  _encodeStringToUTF8(str) {
    const utf8Bytes = [];

    for (let i = 0; i < str.length; i++) {
      let charCode = str.charCodeAt(i);

      // 处理代理对（Surrogate Pair），用于表示大于 0xFFFF 的字符
      if (charCode >= 0xD800 && charCode <= 0xDBFF && i + 1 < str.length) {
        const nextCharCode = str.charCodeAt(i + 1);
        if (nextCharCode >= 0xDC00 && nextCharCode <= 0xDFFF) {
          // 组合代理对
          charCode = 0x10000 + ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00);
          i++;
        }
      }

      // UTF-8 编码
      if (charCode < 0x80) {
        // 1 字节: 0xxxxxxx
        utf8Bytes.push(charCode);
      } else if (charCode < 0x800) {
        // 2 字节: 110xxxxx 10xxxxxx
        utf8Bytes.push(0xC0 | (charCode >> 6));
        utf8Bytes.push(0x80 | (charCode & 0x3F));
      } else if (charCode < 0x10000) {
        // 3 字节: 1110xxxx 10xxxxxx 10xxxxxx
        utf8Bytes.push(0xE0 | (charCode >> 12));
        utf8Bytes.push(0x80 | ((charCode >> 6) & 0x3F));
        utf8Bytes.push(0x80 | (charCode & 0x3F));
      } else {
        // 4 字节: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        utf8Bytes.push(0xF0 | (charCode >> 18));
        utf8Bytes.push(0x80 | ((charCode >> 12) & 0x3F));
        utf8Bytes.push(0x80 | ((charCode >> 6) & 0x3F));
        utf8Bytes.push(0x80 | (charCode & 0x3F));
      }
    }

    return new Uint8Array(utf8Bytes).buffer;
  }

  /**
   * 手动 UTF-8 解码
   */
  _decodeUTF8Array(uint8Array) {
    if (!(uint8Array instanceof Uint8Array)) {
      throw new Error('入参必须为 Uint8Array 类型');
    }

    var out = "";
    var i = 0;
    var len = uint8Array.length;
    var c, char2, char3;

    while (i < len) {
      c = uint8Array[i++];
      switch (c >> 4) {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
          // 0xxxxxxx (单字节字符: ASCII)
          out += String.fromCharCode(c);
          break;
        case 12:
        case 13:
          // 110x xxxx 10xx xxxx (两字节字符)
          if (i >= len) {
            throw new Error('非法的UTF-8序列：两字节字符不完整');
          }
          char2 = uint8Array[i++];
          out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
          break;
        case 14:
          // 1110 xxxx 10xx xxxx 10xx xxxx (三字节字符，如大部分中文)
          if (i + 1 >= len) {
            throw new Error('非法的UTF-8序列：三字节字符不完整');
          }
          char2 = uint8Array[i++];
          char3 = uint8Array[i++];
          out += String.fromCharCode(
            ((c & 0x0F) << 12) |
            ((char2 & 0x3F) << 6) |
            ((char3 & 0x3F) << 0)
          );
          break;
        default:
          // 可能是4字节字符或其他，此处为简化处理可跳过或抛出错误
          // 对于微信小程序与ESP32通讯的中文场景，以上三种情况已基本覆盖
          break;
      }
    }
    return out;
  }

  /**
   * 支持中文字符的字符串到 ArrayBuffer 转换
   */
  stringToArrayBuffer(str) {
    if (this.textEncoder) {
      // 使用 TextEncoder（推荐）
      console.log("use textEncoder")
      return this.textEncoder.encode(str).buffer;
    } else {
      // 兼容方案
      console.log("use _encodeStringToUTF8")
      return this._encodeStringToUTF8(str);
    }
  }

  /**
   * ArrayBuffer 到字符串转换
   */
  arrayBufferToString(buffer, offset = 0, length = null) {
    const uint8Array = new Uint8Array(buffer, offset, length);
    if (this.textDecoder) {
      // 使用 TextDecoder（推荐）
      console.log("use textDecoder")
      return this.textDecoder.decode(buffer);
    } else {
      // 兼容方案
      console.log("use _decodeUTF8Array")
      return this._decodeUTF8Array(uint8Array);
    }
  }











}


export default BleManager;